
'use strict';

const dbConfig = require('./config.json').dbConfig;
const mongoose = require('mongoose');
const dbError = require('./dbError');
const db = mongoose.connect(dbConfig.path);

/**
 * 快递信息文档模式
 */
const expSchema = new mongoose.Schema({
    expNo: { type: String },//快递编号
    expReName: { type: String },//快递收件人姓名
    expReTel: { type: String },//快递收件人电话
    expPay: { type: Number },//快递代收费用
    expCouTel: { type: String },//快递投递人账号
    expCabinetNo: { type: String },//快递所在快递柜编号
    expStatus: { type: String },//快递状态
    expInDate: { type: Date },//快递入柜时间
    expOutDate: { type: Date },//快递出柜时间
    expSmsStatus: { type: String },//快递短信发送状态
});

/**
 * 快递柜信息文档模式
 */
const cabSchema = new mongoose.Schema({
    cabNo: { type: String },//快递柜编号
    cabType: { type: String },//快递柜型号
    cabInUse: { type: Boolean },//快递柜使用状态
    cabPwd: { type: String },//开柜密码
    cabPortName: { type: String },//串口名称
    cabOpenCmd: { type: String },//开柜命令
    cabCheckCmd: { type: String },//检测命令
    cabOpenStatus: { type: String }//打开状态字符串
});

/**
 * 信息记录文档模式
 */
const msgSchema = new mongoose.Schema({
    expNo: { type: String },//快递编号
    msgId: { type: String },//信息ID
    msgStatus: { type: String },//信息发送状态(发送中,发送成功,发送失败)
    msgRepeat: { type: Number, default: 0 }//信息重发次数
});

/**
 * 更新EXP文档中的短信发送状态(expSmsStatus)
 * 
 * @param {string}expNo 快递单号
 * @param {string}msgStatus 信息发送状态
 * @return {Promise}
 */
expSchema.statics.updateMsgStatus = function(expNo, msgStatus) {
    return new Promise((resolve, reject) => {
        let updateCondition = { expNo: expNo };
        let updateData = { expSmsStatus: msgStatus };
        this.update(updateCondition, updateData, function(err, doc) {
            if (err) {
                reject(new dbError.DBUpdateError('updateMsgStatus', updateCondition, updateData, err))
            } else {
                resolve();
            }
        });
    });
}

/**
 * 取得EXP的具体信息
 * 
 * @param {string}expNo 快递单号
 * @return {Promise}
 */
expSchema.statics.getExpByExpNo = function(expNo) {
    return new Promise((resolve, reject) => {
        let searchCondition = { expNo };
        this.findOne(searchCondition, function(err, doc) {
            if (doc) {
                resolve(doc);
            } else {
                reject(new dbError.DBSearchError('getExpByExpNo', searchCondition, err));
            }
        });
    });
}

/**
 * 按照expNo更新msgId、msgRepeat、msgStatus
 * 
 * @param {string}expNo 快递单号
 * @param {string}msgId 信息ID
 * @param {string}msgRepeat 信息发送重复次数
 * @param {string}msgStatus 信息发送状态
 * @return {Promise}
 */
msgSchema.statics.updateMsgId = function(expNo, msgId, msgRepeat, msgStatus) {
    return new Promise((resolve, reject) => {
        let updateCondition = { expNo };
        let updateData = { msgId, msgRepeat, msgStatus };
        this.update(updateCondition, updateData, function(err, doc) {
            if (err) {
                reject(new dbError.DBUpdateError('updateMsgId', updateCondition, updateData, err));
            } else {
                resolve();
            }
        });
    });
}

/**
 * 取得信息发送的重复次数msgRepeat
 * 
 * @param {string}expNo 快递单号
 * @return {Promise}
 */
msgSchema.statics.getMsgRepeat = function(expNo) {
    return new Promise((resolve, reject) => {
        let searchCondition = { expNo };
        this.findOne(searchCondition, function(err, doc) {
            if (doc) {
                resolve(doc.msgRepeat);
            } else {
                reject(new dbError.DBSearchError('getMsgRepeat', searchCondition, err));
            }
        });
    });
}

/**
 * 更新msgStatus
 * 
 * @param {string}msgId 信息ID
 * @param {string}msgStatus 信息发送状态
 * @return {Promise}
 */
msgSchema.statics.updataMsgStatus = function(msgId, msgStatus) {
    return new Promise((resolve, reject) => {
        let updateCondition = { msgId };
        let updateData = { msgStatus };
        this.update(updateCondition, updateData, function(err) {
            if (err) {
                reject(new dbError.DBUpdateError('updataMsgStatus', updateCondition, updateData, err));
            } else {
                resolve();
            }
        });
    });
}

/**
 * 按照msgId删除MSG文档集合中对应的msg文档
 * 
 * @param {string}msgId 信息ID
 * @return {Promise}
 */
msgSchema.statics.deleteMsgByMsgId = function(msgId) {
    return new Promise((resolve, reject) => {
        let deleteCondition = { msgId };
        this.remove(deleteCondition, function(err) {
            if (err) {
                reject(new dbError.DBDeleteError('deleteMsgByMsgId', deleteCondition, err));
            } else {
                resolve();
            }
        });
    });
}

/**
 * 取得需要删除的msg（需要删除是指：已经发送成功，或者发送三次以上仍然失败的）
 * 
 * @return {Promise}
 */
msgSchema.statics.getNeedDelMsg = function() {
    return new Promise((resolve, reject) => {
        let searchCondition = { '$or': [{ msgStatus: '发送成功' }, { msgRepeat: { '$gte': 3 } }] };
        this.find(searchCondition, function(err, doc) {
            if (err) {
                reject(new dbError.DBSearchError('getNeedDelMsg', searchCondition, err));
            } else {
                resolve(doc);
            }
        });
    });
}

/**
 * 取得需要发送的msg（需要发送是指：msgId为null，即从来没发送过，或者发送次数小于3次且发送状态为失败的）
 * 
 * @return {Promise}
 */
msgSchema.statics.getNeedSendMsg = function() {
    return new Promise((resolve, reject) => {
        let searchCondition = { '$or': [{ msgId: null }, { msgStatus: '发送失败', msgRepeat: { '$lt': 3 } }] };
        this.find(searchCondition, function(err, doc) {
            if (err) {
                reject(new dbError.DBSearchError('getNeedSendMsg', searchCondition, err));
            } else {
                resolve(doc);
            }
        });
    });
}

/**
 * 取得cab的详细信息
 * 
 * @param {string}cabNo 快递柜编号
 * @return {Promise}
 */
cabSchema.statics.getCabByCabNo = function(cabNo) {
    return new Promise((resolve, reject) => {
        let searchCondition = { cabNo };
        this.findOne(searchCondition, function(err, doc) {
            if (doc) {
                resolve(doc);
            } else {
                reject(new dbError.DBSearchError('getCabByCabNo', searchCondition, err));
            }
        });
    });
}

/**
 * 转移信息状态，从MSG文档到EXP文档（当信息发送成功，或者发送三次以上仍然失败的，那么更新对应的EXP文档中的信息状态，删除MSG文档中的记录）
 * 
 * @param {Object}expModel 快递信息文档模型
 * @param {Object}msgModel 信息记录文档模型
 * @return {Function*}
 */
function* transferMsgStatusToExp(expModel, msgModel) {
    let msgs = yield msgModel.getNeedDelMsg();
    for (let msg of msgs) {
        yield expModel.updateMsgStatus(msg.expNo, msg.msgStatus);
        yield msgModel.deleteMsgByMsgId(msg.msgId);
    }
}

/**
 * 取得msg发送的次数，更新MSG文档对应的msgId（一般在发送短信之后执行）
 * 
 * @param {string}expNo 快递单号
 * @param {string}msgId 信息ID
 * @param {string}msgStatus 信息发送状态
 * @param {Object}msgModel 信息记录文档模型
 * @return {Function*}
 */
function* updateMsgId(expNo, msgId, msgStatus, msgModel) {
    let msgRepeat = yield msgModel.getMsgRepeat(expNo);
    yield msgModel.updateMsgId(expNo, msgId, msgRepeat + 1, msgStatus)
}

/**
 * 取得exp和cab信息（一般发生在需要发送短信前，用于组装短信的具体信息）
 * 
 * @param {string}expNo 快递单号
 * @param {Object}expModel 快递信息文档模型
 * @param {Object}cabModel 快递柜信息文档模型
 * @return {Function*}
 */
function* getExpCabByExpNo(expNo, expModel, cabModel) {
    let exp = yield expModel.getExpByExpNo(expNo);
    let cab = yield cabModel.getCabByCabNo(exp.expCabinetNo);
    return { exp, cab };
}

/**
 * 快递信息文档模型
 */
const expModel = db.model('exp', expSchema);

/**
 * 快递柜信息文档模型
 */
const cabModel = db.model('cab', cabSchema);

/**
 * 信息记录文档模型
 */
const msgModel = db.model('msg', msgSchema);

module.exports.msgModel = msgModel;
module.exports.expModel = expModel;
module.exports.cabModel = cabModel;
module.exports.transferMsgStatusToExp = transferMsgStatusToExp;
module.exports.updateMsgId = updateMsgId;
module.exports.getExpCabByExpNo = getExpCabByExpNo;